{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "workbookDir: /home/adrisuau/qlm_notebook/notebook/qaths/notebooks\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    import qaths\n",
    "except ImportError:\n",
    "    # If we can't find qaths, then try to add some directory where it could be.\n",
    "    # First, we determine the current notebook directory.\n",
    "    import os\n",
    "    if not 'workbookDir' in globals():\n",
    "        workbookDir = os.getcwd()\n",
    "    print('workbookDir: ' + workbookDir)\n",
    "    \n",
    "    # Then we append the parent directory to the PYTHONPATH because this is how\n",
    "    # qaths is structured for the moment.\n",
    "    import sys\n",
    "    sys.path.append(os.path.dirname(os.path.abspath(workbookDir)))\n",
    "    \n",
    "    # And we try to import qaths again. If it does not work, the import will raise\n",
    "    # an exception and we do not want to handle it in order to stop the execution and \n",
    "    # warn the user.\n",
    "    import qaths"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# File-related operations\n",
    "import os\n",
    "# Parallelisation of computations\n",
    "import concurrent.futures\n",
    "import multiprocessing\n",
    "# Regex searching / replacing\n",
    "import re\n",
    "# Python scientific libraries\n",
    "import numpy\n",
    "import pandas\n",
    "import scipy.optimize as sopt\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.colors\n",
    "# time module to time function execution\n",
    "import time as timemodule\n",
    "\n",
    "# Wave equation quantum solver\n",
    "from qaths.applications.wave_equation.utils import compute_qubit_number_from_considered_points_1D\n",
    "from qaths.applications.wave_equation.evolve_1D_dirichlet import solve_1D_dirichlet_stationary\n",
    "# qat specific \n",
    "from qat.lang.AQASM import Program\n",
    "from qat.graphopt import Graphopt\n",
    "from qat.core.simutil import optimize_circuit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "discretisation_points_number = 100\n",
    "\n",
    "def get_gate_name(gate, gateDic) -> str:\n",
    "    if gate.syntax is not None:\n",
    "        return gate.syntax.name\n",
    "    elif gate.is_ctrl:\n",
    "        return \"CTRL({})\".format(get_gate_name(gateDic[gate.subgate], gateDic))\n",
    "    else:\n",
    "        raise RuntimeError(\"Unsupported operation in get_gate_name: {}\".format(gate))\n",
    "\n",
    "# The value here is not important as the data gathered (gate number, \n",
    "# generation time and arity) does not depend on this value.\n",
    "random_time = 1.07939369\n",
    "\n",
    "res = {\"discretisation_points_number\" : discretisation_points_number}\n",
    "\n",
    "# 1. Generate the quantum circuit\n",
    "n = compute_qubit_number_from_considered_points_1D(discretisation_points_number-2)\n",
    "\n",
    "solve_gate = solve_1D_dirichlet_stationary(random_time, \n",
    "                                           discretisation_points_number, \n",
    "                                           None, \n",
    "                                           1)\n",
    "\n",
    "prog = Program()\n",
    "x = prog.qalloc(n)\n",
    "m = prog.qalloc(n)\n",
    "w = prog.qalloc(1)\n",
    "p = prog.qalloc(1)\n",
    "s = prog.qalloc(1)\n",
    "p2 = prog.qalloc(1)\n",
    "ancilla = prog.qalloc(solve_gate.arity - (2*n+4))\n",
    "\n",
    "prog.apply(solve_gate, \n",
    "           x, m, w, p, s, p2, ancilla)\n",
    "\n",
    "circ = prog.to_circ()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qaths.hardware_models.IBMQ import circ_to_ibmq_basis\n",
    "\n",
    "ibmq_circ = circ_to_ibmq_basis(circ)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original: 21280\n",
      "Expanded: 21280\n",
      "Optimised: 21280\n",
      "IBMQ: 73712\n"
     ]
    }
   ],
   "source": [
    "circ_exp = optimize_circuit(circ, Graphopt(expandonly=True))\n",
    "circ_opt = optimize_circuit(circ_exp, Graphopt())\n",
    "\n",
    "print(\"Original:\", len(circ.ops))\n",
    "print(\"Expanded:\", len(circ_exp.ops))\n",
    "print(\"Optimised:\", len(circ_opt.ops))\n",
    "print(\"IBMQ:\", len(ibmq_circ.ops))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9217010\n"
     ]
    }
   ],
   "source": [
    "from qat.noisy.util import start_and_end_times\n",
    "\n",
    "## A small \"hack\" of a function that creates a space time diagram of the quantum circuit using a map of gate times\n",
    "def get_depth(circuit, gate_times):\n",
    "    \"\"\"\n",
    "    Returns the depth of a circuit given some gate passing times.\n",
    "    \"\"\"\n",
    "    _, start_times, end_times = start_and_end_times(circuit, gate_times)\n",
    "    return max(max(e for e in end_times))\n",
    "\n",
    "gate_times = {\"U1\" : 0, \"U2\" : 100 + 20, \"U3\" : 100 + 20 + 100 + 20, \"CX\": 100 + 20 + 347 + 20 + 100 + 20 + 347 + 20}\n",
    "print(get_depth(ibmq_circ, gate_times))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
